package com.shy.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class OrderController {
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    /**
     * 设置库存
     * @return 返回设置结果
     */
    @RequestMapping("/set_stock")
    public String set_stock() {
        // 使用stringRedisTemplate操作Redis数据库
        stringRedisTemplate.opsForValue().set("stock", "100");
        return "ok";
    }

    /**
     * 减库存方法
     * @param productId 商品ID
     * @return 返回操作结果
     */
    public String deductStock(@PathVariable String productId) {
        String lockKey = "product_" + productId;
        try {
            boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "lock", 30, TimeUnit.SECONDS);
            if (!result) {
                // 如果锁不存在，则使用CAS操作减库存
                result = deductStockCAS(lockKey, 3);

                if (!result) {
                    return "error";
                }
            }
            // 获取库存数量
            Integer stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));

            if (stock > 0) {
                stock -= 1;
                stringRedisTemplate.opsForValue().set("stock", stock.toString());
                System.out.println("库存扣减成功，剩余库存:" + stock);
                return "success";
            }
            System.out.println("库存不足，扣除失败！");
            return "error";
        } finally {
            // 删除锁
            stringRedisTemplate.delete(lockKey);
        }
    }

    /**
     * 设置要获取的key和尝试的次数
     * 没有获取到锁,通过CAS自旋
     * CAS方式扣除库存
     * @param lockKey 锁定key
     * @param count 要扣除的库存数量
     * @return 如果成功扣除库存返回true，否则返回false
     */
    public boolean deductStockCAS(String lockKey, Integer count) {
        try {
            int i = 0;
            do {
                Thread.sleep(1000L);
                i++;
                if (i == count + 1) {// 自旋结果
                    return false;
                }
            } while (!stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "lock", 30, TimeUnit.SECONDS));
            return true;
        } catch (InterruptedException e) {
            return false;
        }
    }

}
